﻿
namespace EasyStep.Business.Managers.FileSystem
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using EasyStep.Business.Interfaces;
    using EasyStep.Data.Entities;
    using System.IO;


    public class TestInfoManager : ITestInfoManager
    {
        public const string testFileSuffix = ".test.csv";
        private ITestDataContext Context { get; set; }
        public TestInfoManager(ITestDataContext context)
        {
            Context = context;
        }
        public TestInfo Get(Guid id)
        {
            throw new NotImplementedException();
        }

        public IEnumerable<TestInfo> GetProjectTests(string projectName=null)
        {
            if (string.IsNullOrEmpty(projectName)) projectName=Context.CurrentProject ;
            if (string.IsNullOrEmpty(projectName))
                throw new NotSupportedException("Project have to be specified!");
            return
                Directory.EnumerateFiles(projectName, string.Concat("*", testFileSuffix), SearchOption.TopDirectoryOnly)
                .Select(f => new TestInfo() { Name = Path.GetFileName(f), Project=projectName });
        }

        public TestInfo GetTest(string projectName = null, string testName = null, bool withSteps = false)
        {            
            if (Path.IsPathRooted(testName))
            {
                projectName = Path.GetDirectoryName(testName);
                testName = Path.GetFileName(testName);
            }
            if (string.IsNullOrEmpty(testName)) testName = Context.CurrentTest;            
            if (string.IsNullOrEmpty(testName))
                throw new NotSupportedException("Test Name have to be specified!");
            
            testName=Path.GetFileName(testName);
            testName = AddSuffix(testName, testFileSuffix);
            var result = GetProjectTests(projectName)
                .Where(t => t.Name.Equals(testName, StringComparison.OrdinalIgnoreCase))
                .FirstOrDefault();
            
                
            if (withSteps && result != null)
            {
                var testFilename = Path.Combine(result.Project, result.Name);
                TestInfo stepsData = null;
                using (var fs = File.OpenRead(testFilename))
                using (var sr = new StreamReader(fs))
                    stepsData = Convert(sr);

                if (stepsData == null) result.Steps = new TestStep[] { };
                else
                {
                    var steps = stepsData.Steps.ToList();
                    var i = 0;
                    steps.ForEach(s => { s.Test = result; s.OrderNr = ++i; });//assign reference to test -needed
                    result.Steps = steps;
                }

            }
            return result;
        }

       


        public TestInfo Create(TestInfo data)
        {
            //todo:update cache
            if (Path.IsPathRooted(data.Name))
                data.Name = Path.GetFileName(data.Name);

            var existing = GetTest(data.Project,data.Name);
            if (existing != null) throw new ArgumentException("Can't create test, with name of already existing one: " + data.Project+","+data.Name);
            var projectName = string.IsNullOrEmpty(data.Project) ? Context.CurrentProject : data.Project;
            var testFilename = Path.Combine(projectName, data.Name);
            File.WriteAllText(testFilename, Convert(data));
            return data;
        }

        public TestInfo Update(TestInfo data)
        {
            EnsureTestExist(data, (f) =>
            {//todo:update cache
                File.WriteAllText(f, Convert(data));
            });
            return data;
        }

        public TestInfo Delete(TestInfo data)
        {
            EnsureTestExist(data, (f) =>
            {//todo:update cache
                File.Delete(f);
            });
            return data;
        }

        private void EnsureTestExist(TestInfo data, Action<string> onExist)
        {
            if (Path.IsPathRooted(data.Name))
            {
                data.Name = Path.GetFileName(data.Name);
                data.Project = Path.GetDirectoryName(data.Name);
            }
            if (string.IsNullOrEmpty(data.Project)) data.Project = Context.CurrentProject;
            var existing = GetTest(data.Project, data.Name);
            if (existing == null) throw new ArgumentException("Can't find test, with name : " + data.Name);
            var testFilename = Path.Combine(data.Project, data.Name);
            onExist(testFilename);
        }

        public string Convert(TestInfo item)
        {
            if (item == null || item.Steps == null) return string.Empty;
            var sb = new StringBuilder();
            foreach (var sitem in item.Steps)
                sb.AppendLine(Context.TestStepManager.Convert(sitem));
            return sb.ToString();
        }

        public TestInfo Convert(StreamReader data)
        {
            if (data == null) return null;
            var ti = new TestInfo();
            var steps = new List<TestStep>();
            var i = 0;
            while (!data.EndOfStream)//read 
            {
                var line = data.ReadLine();
                if (string.IsNullOrEmpty(line)) continue;
                
                var step = Context.TestStepManager.Convert(line);
                if (step != null)
                {
                    step.OrderNr = ++i;
                    steps.Add(step);
                }
            }
            ti.Steps = steps;
            return ti;
        }

        //private string RemoveSuffix(string fileName, string suffix)
        //{
        //    return fileName.EndsWith(suffix, StringComparison.OrdinalIgnoreCase)
        //        ? fileName.Substring(0, fileName.Length - suffix.Length)
        //        : fileName;
        //}
        private string AddSuffix(string fileName, string suffix)
        {
            return fileName.EndsWith(suffix, StringComparison.OrdinalIgnoreCase)
                ? fileName
                : string.Concat(fileName, suffix);
        }



    }
}
